"use strict";
// 抽象类
// 概述： 抽象类是一种无法被实例化的类，专门用来定义类的结构和行为，类中可以写抽象方法，也可以写具体方法。
//        抽象类主要用来为其派生类提供一个基础结构，要求其派生类必须实现其中的抽象方法
// 简记：  抽象类不能实例化，其意义是可以被继承，抽象类里可以有普通方法、也可以有抽象方法
// 通过以下场景理解抽象类：
//     我们定义一个抽象类Package,表示所有包裹的基本机构，任何包裹都有重量属性weight，包裹都需要计算运费。
// 但不同类型的包裹(如：标准快递、特快快递)都有不同的运费计算方式，因此用于计算运费的calculate方法是一个抽象方法，必须由具体的子类来实现
// 抽象类需要在 class 关键字前面加上 abstract 关键字，用于定义抽象类
class Package {
    // 构造器
    constructor(name, weight) {
        this.name = name;
        this.weight = weight;
    }
    // 具体方法
    printPackage() {
        console.log(`${this.name},包裹重量为:${this.weight}kg,运费为:${this.calculate()}元`);
    }
}
// const package1 = new Package('面包',10)   //报错，因为抽象类不能用new关键字实例化，
// 原理很好理解，假如实例化了上面抽象类，然后调用了具体方法printPackage，然后函数体里调用了抽象方法，但是calculate都没有函数体，怎么调用呢。
// 抽象类只能被继承，不能被实例化
// 标准包裹
class StandarPackage extends Package {
    constructor(
    // name和weight不需要再用修饰符修饰了，因为定义抽象类时已经修饰了
    name, weight, unitPrice) {
        // 类继承的关键字 super，作用类似vue的$emit,把获得的值提交给父类
        super(name, weight);
        this.unitPrice = unitPrice;
    }
    calculate() {
        return this.weight * this.unitPrice;
    }
}
const standar = new StandarPackage('电脑主机', 10, 5);
standar.printPackage();
// 特快包裹
class ExpressPackage extends Package {
    constructor(
    // name和weight不需要再用修饰符修饰了，因为定义抽象类时已经修饰了
    name, weight, 
    // 单价
    unitPrice, 
    // 附加价
    addPrice) {
        // 类继承的关键字 super，作用类似vue的$emit,把获得的值提交给父类
        super(name, weight);
        this.unitPrice = unitPrice;
        this.addPrice = addPrice;
    }
    calculate() {
        if (this.weight > 10) {
            // 超出10kg，每公斤加收3元
            return 10 * this.unitPrice + (this.weight - 10) * this.addPrice;
        }
        else {
            return this.weight * this.unitPrice;
        }
    }
}
const expresspack = new ExpressPackage('草莓', 18, 8, 3);
expresspack.printPackage();
// 总结：何时使用抽象类?
//   1、定义通用接口：为一组相关的类定义通用的行为(方法和属性)时
//   2、提供基础实现:在抽象类中提供某些方法或为其提供基础实现，这样派生类就可以继承这些实现
//   3、确保关键是实现:强制派生类实现一些关键行为
//   4、共享代码和逻辑：当多个类需要共享部分代码时，抽象类可以避免代码重复
